<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2018/8/9
 * Time: 13:59
 */

namespace app\web\controller;

use app\api\controller\v2\Auth;
use app\common\cachemodel\AppQq;
use app\common\cachemodel\AppSynastryResult;
use app\common\cachemodel\AppSynastryResult2021;
use app\common\cachemodel\Goods;
use app\common\cachemodel\NatalGoods;
use app\common\cachemodel\Orders as OrdersModel;
use app\common\cachemodel\Recode as RecodeCacheModel;
use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\Wechat;
use app\common\cachemodel\ZlRecordShareAdd;
use app\common\lib\Aes;
use app\common\lib\astrolog\Astrolog;
use app\common\lib\astrolog\SynastryData;
use app\common\lib\exception\ApiException;
use app\common\lib\IAuth;
use app\common\lib\Push;
use app\common\lib\Util;
use app\common\model\MessageCenter;
use app\common\model\Recode;
use app\common\model\User;
use \think\Controller;
use \app\common\lib\Jssdk;
use think\Db;
use think\Env;
use think\Exception;
use think\Log;
use think\response\Json;

class Valentine extends Controller
{
    protected $noNeedJudgeSummer = ['香港特别行政区', '澳门特别行政区', '台湾省', '北美洲', '大洋洲', '非洲', '南美洲', '欧洲', '亚洲', ''];
    private $headers = [];
    private $oss = '';
    private $domain = '';
    //微信分享图片
    protected $share_img = '';
    protected $LOG_PRE = '邀请合盘错误：';

    public function _initialize(): void
    {
        $this->oss = Env::get('host.photo');
        $this->domain = Env::get('host.domain');
        $this->share_img = $this->oss . 'web/invitate_input_record/images/share_logo.png';
    }

    public function index()
    {
        $signPackage = (new Jssdk())->getSignPackage();

        return $this->fetch('index', [
            'title' => '十二星座土味情话小纸条',
            'share_title' => '你收到了一张表白小纸条',
            'share_introduction' => '七夕，最好的礼物是表白',
            'signPackage' => $signPackage
        ]);
    }

    public function add()
    {
        $signPackage = (new Jssdk())->getSignPackage();

        return $this->fetch('add', [
            'title' => '十二星座土味情话小纸条',
            'share_title' => '你收到了一张表白小纸条',
            'share_introduction' => '七夕，最好的礼物是表白',
            'signPackage' => $signPackage
        ]);
    }

    public function save()
    {
        $signPackage = (new Jssdk())->getSignPackage();

        $name1 = htmlspecialchars(trim(input('post.name1/s')));
        $name2 = htmlspecialchars(trim(input('post.name2/s')));
        $sign_id = input('post.sign/d');

        if ($name1 == '' || $name2 == '' || $sign_id <= 0 || $sign_id > 12)
        {
            $this->redirect('/activity/valentine');
        }

        if (mb_strlen($name1) > 4)
        {
            $name1 = mb_substr($name1, 0, 4) . '...';
        }

        if (mb_strlen($name2) > 7)
        {
            $name2 = mb_substr($name2, 0, 7) . '...';
        }

        $data = [
            'name1' => $name1,
            'name2' => $name2,
            'sign' => $sign_id . '-' . rand(1, 4),
            'sign_id' => $sign_id,
        ];

        return $this->fetch('save', [
            'title' => '十二星座土味情话小纸条',
            'share_title' => '你收到了一张表白小纸条',
            'share_introduction' => '七夕，最好的礼物是表白',
            'signPackage' => $signPackage,
            'data' => $data,
        ]);
    }

    public function composite()
    {
        $signPackage = (new Jssdk())->getSignPackage();

        return $this->fetch('composite', [
            'title' => '揭开情侣关系真相',
            'share_title' => '星盘合盘解读',
            'share_introduction' => '看你与异性是否契合',
            'signPackage' => $signPackage
        ]);
    }

    /**
     * 生成标签图片
     */
    public function img()
    {
        $name1 = htmlspecialchars(trim(input('get.name1/s')));
        $name2 = htmlspecialchars(trim(input('get.name2/s')));
        $sign = htmlspecialchars(trim(input('get.sign/s')));

        $signid = (int)(explode('-', $sign)[0]);

        $quar = $signid % 4;

        $from_x = 1100;

        $from_name_x = 1343;

        $name1_mb_len = mb_strlen($name1, 'utf8');
        $name1_len = strlen($name1);

        if ($name1_len != $name1_mb_len)
        {
            $from_x += (3 - $name1_mb_len) * 100;
            $from_name_x += (3 - $name1_mb_len) * 100;
            if (mb_substr($name1, -3, 3) === '...')
            {
                $from_x += 220;
                $from_name_x += 220;
            }
        } else
        {
            $from_x += (3 - $name1_len) * 110;
            $from_name_x += (3 - $name1_len) * 110;
            if (mb_substr($name1, -3, 3) === '...')
            {
                $from_x += 440;
                $from_name_x += 440;
            }
        }


        header("Content-type: image/png");

        $im = @imagecreatetruecolor(2250, 3672) or die("Cannot initialize new GD image stream");

        if ($quar == 1)
        {
            $bg_color = imagecolorallocate($im, 250, 238, 238);
            $name_color = imagecolorallocate($im, 60, 99, 191);
        } elseif ($quar == 2)
        {
            $bg_color = imagecolorallocate($im, 28, 213, 175);
            $name_color = imagecolorallocate($im, 42, 100, 183);
        } elseif ($quar == 3)
        {
            $bg_color = imagecolorallocate($im, 31, 186, 101);
            $name_color = imagecolorallocate($im, 35, 181, 101);
        } else
        {
            $bg_color = imagecolorallocate($im, 73, 95, 171);
            $name_color = imagecolorallocate($im, 81, 242, 213);
        }

        imagefilledrectangle($im, 0, 0, 2250, 3672, $bg_color);// 创建画布

        $im2 = imagecreatefromstring(file_get_contents('./static/valentine/img/' . $sign . '.png'));
        imagecopymerge($im, $im2, 159, 120, 0, 0, imagesx($im2), imagesy($im2), 100);

        $im3 = imagecreatefromstring(file_get_contents('./static/valentine/img/footer-' . $quar . '.png'));
        imagecopymerge($im, $im3, 159, 2868, 0, 0, imagesx($im3), imagesy($im3), 100);

        imagettftext($im, 75, 0, 447, 704, $name_color, './static/valentine/SimSun.ttf', 'To / ' . $name2);
        imagettftext($im, 80, 0, $from_x, 2376, $name_color, './static/valentine/SimSun.ttf', 'From');
        imagettftext($im, 60, 0, $from_name_x, 2376, $name_color, './static/valentine/SimSun.ttf', '/ ' . $name1);


        imagejpeg($im);
        imagedestroy($im);
        exit();
    }

    /**
     * 2020年七夕节合盘活动
     * @return mixed
     */
    public function index2020()
    {
        $debug = false;

        // 检查运行环境：true => 运行在APP内 , false => 在APP外的请求
        $rn = $this->checkRuntimeEnvironment();

        if ($debug === true)
        {
            $rn = true;
        }
        // 获取用户的合盘记录
        if ($rn === true)
        {
            //校验token
            try
            {
                $AppSynastryResult = new AppSynastryResult();
                $nowTime = time();
                $auth = new Auth();
                $uid = (int)$auth->user['id'];

                $rank = $AppSynastryResult->userRankingIndex($uid);

                if ($rank === 0)
                {
                    $rank = '100+';
                }
                $userinfo = [
                    'id' => $uid,
                    'nickname' => $auth->user['nickname'],
                    'avatar' => $auth->user['avatar'],
                    'userHistory' => $AppSynastryResult->getUserHighestScore($uid),
                    'userRank' => $rank,
                    // 'show_type' => 1  查看合盘结果时，显示完整版结果
                    'token_weixin' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => $nowTime, 'share_to' => 1, 'show_type' => 1])),
                    'token_qq' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => $nowTime, 'share_to' => 2, 'show_type' => 1])),
                ];
            }
            catch (Exception $e)
            {
                throw new ApiException('合盘错误：权限认证失败,请稍后重试！');
            }
        } else
        {
            $userinfo = [
                'id' => '',
                'nickname' => '',
                'avatar' => '',
                'userHistory' => [],
                'token_weixin' => '',
                'token_qq' => '',
            ];
        }

        return $this->fetch('', [
            'rn' => $rn,
            'userinfo' => $userinfo,
            'title' => '七夕来合盘，爱让所有人看见',
            'share_introduction' => '',//七夕免费赢取恋爱报告的机会就在这里！
            // 获取恋爱报告售卖数量 TODO 获取恋爱报告配色
            'love_report_sale_num' => (new OrdersModel())->getTotalPrepaidOrder(7, 39),
            'app_type' => $this->headers['app-type'] ?? '',
            'version' => $this->headers['version'] ?? '',
            'oss' => $this->oss,
            'domain' => $this->domain,
            'share_title' => '七夕敢不敢玩合盘配对，200分以下互删，400分以上扯证！',// 敢不敢和我来合盘，一起挑战最佳拍档！ 七夕敢不敢玩合盘配对，200分以下互删，400分以上扯证！
            'share_des' => '这个七夕玩把刺激的！你敢吗？',//200分以下咱互删，400分以上一起扯证吧！  这个七夕玩把刺激的！你敢吗？
        ]);
    }

    /**
     * 检测七夕活动运行环境
     * 在APP内容使用时必须登录状态，且必须有自己的档案
     */
    protected function checkRuntimeEnvironment()
    {
        // 首先需要获取headers
        $this->headers = $this->request->header();
        if (isset($this->headers['sign'])
            && strpos(config('app.app_types'), $this->headers['app-type']) !== true
            && IAuth::checkSignPass($this->headers))
        {
            return true;
        }

        return false;
    }

    /**
     * 微信/qq档案邀请-填写档案信息页面
     * @return mixed|Json
     * @throws \Exception
     */
    public function add2020()
    {
        $token = input('token/s', '');
        // access-token AES解密
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));
        if (empty($str))
        {
            throw new ApiException($this->LOG_PRE . '参数错误');
        }

        parse_str($str, $params);
        //检查session，如果不存在，那么就直接跳转到登录
        $this->checkLogin($token, $params['share_to']);

        //检查输入参数是否正确
        if (!isset($params['uid']))
        {
            throw new ApiException($this->LOG_PRE . 'uid参数为空');
        }
        if (!isset($params['timestamp']))
        {
            throw new ApiException($this->LOG_PRE . 'timestamp参数为空');
        }
        if (!isset($params['share_to']))
        {
            throw new ApiException($this->LOG_PRE . 'share_to参数为空');
        }
        if (isset($params['share_to']) && ($params['share_to'] * 1 !== 1 && $params['share_to'] * 1 !== 2))
        {
            throw new ApiException($this->LOG_PRE . 'share_to参数错误，只能为【1：微信；2：qq】，实际为' . $params['share_to']);
        }
        try
        {
            $record = [
                'uid' => '',
                'name' => '',
                'sex' => '',
                'year' => '',
                'month' => '',
                'day' => '',
                'hour' => '',
                'minute' => '',
                'timezone' => '',
                'birth_country' => '',
                'birth_province' => '',
                'birth_city' => '',
                'live_country' => '',
                'live_province' => '',
                'live_city' => '',
                'comments' => '',
                'isself' => '',
                'long_deg' => '',
                'long_min' => '',
                'ew' => '',
                'lat_deg' => '',
                'lat_min' => '',
                'ns' => '',
                'avatar' => '',
            ];
            $is_user_have_record = 0;
            $signPackage = [];

            $session_avatar = session('qq.headimgurl');
            $session_sex = session('qq.sex');
            $session_name = session('qq.name');
            $session_unionid = session('qq.unionid');
            if (1 === $params['share_to'] * 1)
            {
                $session_avatar = session('love.headimgurl');
                $session_sex = session('love.sex');
                $session_name = session('love.name');
                $session_unionid = session('love.unionid');
            }

            $data = [
                'uid' => $params['uid'],//用户id
                'status' => '0',//0：填写信息；1：已填写；2：提交成功；3：自己邀请自己，提示错误；4：请从qq或者微信打开；【这里只能输入1/2】
                'is_user_have_record' => 0,//根据unionid查询这个用户是否已经存在档案
                'inviter_name' => '',//邀请者的名字
                'share_to' => $params['share_to'],//【1：微信；2：qq】
                'signPackage' => $signPackage,//微信签名
                'unionid' => $session_unionid,
                'timestamp' => $params['timestamp'],
                'record' => $record
            ];

            $AppWechat = new Wechat();
            $AppQq = new AppQq();
            $Record = new Recode();

            //查询是邀请者自己点击进入的邀请h5，那么就直接提示错误
            if (1 === $params['share_to'] * 1)
            {//微信登录
                $wechat_info = $AppWechat->getWechatInfo($params['uid'], 2);
                if ($wechat_info && isset($wechat_info['unionid']) && $wechat_info['unionid'] === $session_unionid)
                {//用户绑定了微信，自己邀请了自己
                    $data['status'] = 3;
                }
            } else
            {
                //qq登录
                $qq_info = $AppQq->getUserQqInfoFromCache($params['uid'], 2);
                if ($qq_info && isset($qq_info['unionid']) && $qq_info['unionid'] === $session_unionid)
                {//用户绑定了qq，自己邀请了自己
                    $data['status'] = 3;
                }
            }

            if (!isset($data['status']) || (isset($data['status']) && 3 !== $data['status'] * 1))
            {
                //根据unionid查询这个用户，是否微信/qq注册过
                if (1 === $params['share_to'] * 1)
                {//微信登录
                    $appWechat = $AppWechat->getWechatInfo($session_unionid, 1);
                    if (isset($appWechat['uid']))
                    {
                        //查询这个用户是否有自己的档案
                        $recordTemp = $Record->getSelfRecode($appWechat);
                        if ($recordTemp)
                        {
                            $record = $recordTemp;
                            $is_user_have_record = 1;
                        }
                    }
                } else
                {
                    //qq登录
                    $appQq = $AppQq->getUserQqInfoFromCache($session_unionid);
                    if (isset($appQq['uid']))
                    {
                        $recordTemp = $Record->getSelfRecode($appQq);
                        if ($recordTemp)
                        {
                            $record = $recordTemp;
                            $is_user_have_record = 1;
                        }
                    }
                }

                $ZlRecordShareAdd = new ZlRecordShareAdd();
//                $shareStatus = $ZlRecordShareAdd->hasAddRecord($params['share_to'], $session_unionid, $params['timestamp']);
                // TODO 接入缓存
                $shareId = $ZlRecordShareAdd
                    ->where('type', $params['share_to'])
                    ->where('code', $session_unionid)
                    ->where('time', $params['timestamp'])
                    ->value('id');

                if ($shareId)
                {//查到了这个用户，需要提示用户已经填写过了
                    $status = 1;
                } else
                {//没有查到这个用户，需要用户填写
                    $status = 0;
                }
                //查询邀请者的名字
                $inviter = (new User())->getUserinfo(['id' => $params['uid']]);
                $inviter_name = $inviter['nickname'];

                //---数据处理---
                //替换type为sex
                if (isset($record['type']))
                {
                    $record['sex'] = $record['type'];
                }
                //替换avatar
                if (isset($record['avatar']))
                {
                    $avatar = $record['avatar'];
                    $preg = "/^http(s)?:\\/\\/.+/";
                    if (!preg_match($preg, $avatar))
                    {
                        $avatar_tmp = substr($avatar, 0, 1);
                        if ($avatar_tmp === '/')
                        {
                            $record['avatar'] = $this->oss . substr($avatar, 1, strlen($avatar));
                        } else
                        {
                            $record['avatar'] = $this->oss . $avatar;
                        }

                    }
                }
                //---数据处理---
                $data = [
                    'uid' => $params['uid'],//用户id
                    'status' => $status,//0：填写信息；1：已填写；2：提交成功；3：自己邀请自己，提示错误；4：请从qq或者微信打开；【这里只能输入1/2】
                    'record' => $record,
                    'is_user_have_record' => $is_user_have_record,//根据unionid查询这个用户是否已经存在档案
                    'inviter_name' => $inviter_name,//邀请者的名字
                    'share_to' => $params['share_to'],//【1：微信；2：qq】
                    'unionid' => $session_unionid,
                    'timestamp' => $params['timestamp'],
                    'share_id' => $shareId,// 用户已填写的档案在zl_record_share_add表中的id
                    'token' => base64_encode(IAuth::setSign(['uid' => $params['uid'], 'timestamp' => time(), 'show_type' => 0])),
                ];
            }

            if (!$is_user_have_record)
            {//如果用户没有档案，那么就把头像、昵称、性别传过去
                $data['record']['avatar'] = $session_avatar;
                $data['record']['sex'] = $session_sex;
                $data['record']['name'] = $session_name;
            } else
            {
                try
                {
                    //如果用户有档案，获取用户的现居地和出生地，省市区的code
                    $locations = Astrolog::getInstance()->getLocations();
                    $item = $locations[$data['record']['birth_country'] . '-' . $data['record']['birth_province'] . '-' . $data['record']['birth_city']];
                    $data['record']['code_birth_country'] = $item['code_country'];
                    $data['record']['code_birth_province'] = $item['code_province'];
                    $data['record']['code_birth_city'] = $item['code_city'];

                    $item = $locations[$data['record']['live_country'] . '-' . $data['record']['live_province'] . '-' . $data['record']['live_city']];
                    $data['record']['code_live_country'] = $item['code_country'];
                    $data['record']['code_live_province'] = $item['code_province'];
                    $data['record']['code_live_city'] = $item['code_city'];
                }
                catch (\Exception $e)
                {
                    //用户有档案，但是【获取用户的现居地和出生地，省市区的code】出错
                    $data['record']['avatar'] = $session_avatar;
                    $data['record']['sex'] = $session_sex;
                    $data['record']['name'] = $session_name;
                }
            }
            if (1 === $params['share_to'] * 1)
            {
                //微信分享的获取微信js签名
                $signPackage = (new Jssdk())->getSignPackage();
            }

            //时间小于10，加0补充
            $data['record']['month'] = str_pad($data['record']['month'], 2, '0', STR_PAD_LEFT);
            $data['record']['day'] = str_pad($data['record']['day'], 2, '0', STR_PAD_LEFT);
            $data['record']['hour'] = str_pad($data['record']['hour'], 2, '0', STR_PAD_LEFT);
            $data['record']['minute'] = str_pad($data['record']['minute'], 2, '0', STR_PAD_LEFT);

            return $this->fetch('add2020', [
                'title' => '填写你的星盘配置',//网页标题
                'share_title' => '快来跟我合个盘',//微信分享标题. 填写你的星盘配置
                'share_introduction' => '200分以下咱互删，400分以上一起扯证吧！',//微信分享内容 一起刷新合盘榜，来拿恋爱报告！
                'share_img' => $this->share_img,
                'signPackage' => $signPackage,//微信签名
                'data' => $data,//带过去的数据
                'oss' => $this->oss,
                'domain' => $this->domain,
            ]);
        }
        catch (\Exception $e)
        {
            throw new ApiException('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . '：[uid=' . $params['uid'] . '&timestamp=' . $params['timestamp'] . '&share_to=' . $params['share_to'] . ']' . $e->getMessage());
        }

    }

    /**
     * 获取合盘分数排行榜
     */
    public function getRankList()
    {
        $dataList = (new AppSynastryResult())->getList();

        $dataList['code'] = 200;
        $dataList['msg'] = '加载成功';

        return json($dataList);
    }

    /**
     * 档案信息保存
     * @return Json
     */
    public function saveRecord(): Json
    {
        //根据unionid查询这个用户是否已经存在档案；0：不存在；1：已存在；
        $is_user_have_record = input('is_user_have_record/d');
        $share_to = input('share_to/d');
        $timestamp = input('timestamp/d');
        $unionid = input('unionid/s', '', 'htmlspecialchars');// 档案名称;
        $uid = input('uid/d');//用户的id，此处是邀请者

        //检查输入参数是否正确
        if (empty($uid))
        {
            return show(config('code.error'), 'uid参数为空');
        }
        if (empty($timestamp))
        {
            return show(config('code.error'), 'timestamp参数为空');
        }
        if (empty($unionid))
        {
            return show(config('code.error'), 'unionid参数为空');
        }
        if (empty($share_to))
        {
            return show(config('code.error'), 'share_to参数为空');
        }
        if ($share_to * 1 !== 1 && $share_to * 1 !== 2)
        {
            return show(config('code.error'), 'share_to参数错误');
        }

        // 档案标签如 自己 朋友 案例
        $isself = 0;//input('isself/d');// 档案是否为自己 0 否 | 1 是（自己的档案无法删除，无法更改为其他标签）
        $comments = '朋友';//标签，默认为朋友

        $name = input('name/s', '', 'htmlspecialchars');// 档案名称
        $type = input('sex/d', 1);// 档案类型  1男 | 2 女 | 3 男同 | 4 女同 | 5 事件 | 6 卜卦
        if (!$type)
        {
            return show(config('code.error'), '请选择性别！');
        }
        if (!in_array($type, [1, 2, 3, 4, 5, 6], true))
        {
            return show(config('code.error'), '性别异常，请重新选择性别');
        }
        $year = input('year/d');// 出生时间-年
        $month = input('month/d');// 出生时间-月
        $day = input('day/d');// 出生时间-日
        $hour = input('hour/d');// 出生时间-时
        $minute = input('minute/d');// 出生时间-分
        $timezone = input('timezone/d', 8);// 出生时间-时区
        $birth_country = input('birth_country/s', '', 'htmlspecialchars');// 出生地点-省
        $birth_province = input('birth_province/s', '', 'htmlspecialchars');// 出生地点-市
        $birth_city = input('birth_city/s', '', 'htmlspecialchars');// 出生地点-区
        $live_country = input('live_country/s', '', 'htmlspecialchars');// 现居地-省
        $live_province = input('live_province/s', '', 'htmlspecialchars');// 现居地-省
        $live_city = input('live_city/s', '', 'htmlspecialchars');// 现居地-省
        $long_deg = input('long_deg/d');// 经度-度
        $long_min = input('long_min/d');// 经度-分
        $ew = input('ew/d');// 东经|西经 1|-1
        $lat_deg = input('lat_deg/d');// 纬度-度
        $lat_min = input('lat_min/d');// 纬度-分
        $ns = input('ns/d');// 南纬北纬  1|-1
        $avatar = input('avatar/s', '', 'htmlspecialchars_decode');// 头像地址

        $is_summer = 0;
        // 只判断大陆地区的夏令时
        if (!in_array($birth_country, $this->noNeedJudgeSummer, true))
        {
            $is_summer = isSummerTime($hour, $minute, 0, $month, $day, $year) ? 1 : 0;// 是否开启夏令时
        }

        $data = [
            'uid' => $uid,
            'name' => $name,
            'type' => $type,
            'year' => $year,
            'month' => $month,
            'day' => $day,
            'hour' => $hour,
            'minute' => $minute,
            'timezone' => $timezone,
            'birth_country' => $birth_country,
            'birth_province' => $birth_province,
            'birth_city' => $birth_city,
            'live_country' => $live_country,
            'live_province' => $live_province,
            'live_city' => $live_city,
            'comments' => $comments,
            'isself' => $isself,
            'long_deg' => $long_deg,
            'long_min' => $long_min,
            'ew' => $ew,
            'lat_deg' => $lat_deg,
            'lat_min' => $lat_min,
            'ns' => $ns,
            'avatar' => $avatar,
            'is_summer' => $is_summer,
            'add_type' => 2,// 1自己创建 2朋友添加 3注册默认创建
            'is_read' => 0, // 是否已读 1已读 0未读
        ];
        $validate = validate('Recode');

        if (!$validate->scene('add')->check($data))
        {
            return show(config('code.error'), (string)$validate->getError());
        }
        try
        {
            if (!$is_user_have_record)
            {//头像是被邀请者，微信/qq授权获取的，需要上传到oss
                $avatarInfo = Util::wxImgUploadOss($avatar, 'uploads/avatar');
                $avatar = $avatarInfo['success'] ? $avatarInfo['url'] : $avatar;
                $data['avatar'] = $avatar;
            }
            // 替换掉oss域名
            $data['avatar'] = str_replace($this->oss, '', $data['avatar']);

            $record_share_add = [
                'uid' => $uid,
                'rid' => 0,
//            'name' => $name, // 没有，用户使用第三方登录的时候，再去获取
                'type' => $share_to,
                'sex' => $type,
                'code' => $unionid,
                'time' => $timestamp,
                'year' => $year,
                'month' => $month,
                'day' => $day,
                'hour' => $hour,
                'minute' => $minute,
//            'timezone' => $timezone, 这里默认都是8
                'birth_country' => $birth_country,
                'birth_province' => $birth_province,
                'birth_city' => $birth_city,
                'live_country' => $live_country,
                'live_province' => $live_province,
                'live_city' => $live_city,
//            'comments' => $comments,
//            'isself' => $isself,
                'long_deg' => $long_deg,
                'long_min' => $long_min,
                'ew' => $ew,
                'lat_deg' => $lat_deg,
                'lat_min' => $lat_min,
                'ns' => $ns,
                'create_time' => $this->request->time()
//            'avatar' => $avatar, //没有，用户使用第三方登录的时候，再去获取
//            'is_summer' => $is_summer,
            ];
            $ZlRecordShareAdd = new ZlRecordShareAdd();
            $shareId = $ZlRecordShareAdd->SaveData($record_share_add);
        }
        catch (\Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            return show(config('code.error'), '服务异常，请稍后重试！');
        }

        try
        {
            // 获取合盘关系与分数 并入库 更新排行榜
            $RecodeCacheModel = new RecodeCacheModel();
            // 获取用户自己的档案
            $orginSelfRecode = $RecodeCacheModel->getRecodeLists($uid, 1);
            $options = [
                'recode1' => $orginSelfRecode,
                'recode2' => $data,// 刚添加的档案
                'type' => 0,// 获取简易数据，只需要分数和最佳关系
            ];
            $synastryResult = (new SynastryData())->getScore($options);

            $synastryResultInsertData = [
                'uid' => $uid,
                'score' => $synastryResult['scoreNum'],
                'share_id' => $shareId,
                'create_time' => $this->request->time(),
                'nickname1' => $orginSelfRecode['name'],
                'nickname2' => $data['name'],
                'avatar1' => $orginSelfRecode['avatar'],
                'avatar2' => $data['avatar'],
                'relation' => $synastryResult['relationText'],
                'extra' => json_encode([
                    'recode1' => $orginSelfRecode,
                    'recode2' => $data
                ]),
            ];

            $resultId = (new AppSynastryResult())->saveData($synastryResultInsertData, true);
        }
        catch (\Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            return show(config('code.error'), '服务异常，请稍后重试！');
        }

        // 消息中心添加信息
        $messageData = [
            'status' => 0,
            'is_read' => 0,
            'range' => $uid,
            'type' => 2,
            'reid' => 0,
            'cid' => 0,
            'title' => '好友助力冲榜已完成',
            'content' => '快来查看你和"' . $data['name'] . '"的上榜情况!',
            'link' => $this->domain . '/web/valentine/index2020?need_auth=1',
            'target' => 'link',
            'create_time' => $this->request->time()
        ];
        //发送消息
        try
        {
            //推送消息
            (new Push())->pushUserMsg($uid, $messageData['content'], ['action' => 'valentine2020'], $messageData['title']);
            //消息中心增加消息
            (new MessageCenter())->pushMessage($uid, $messageData);
            // 记录档案更新状态
            $RecodeCacheModel->setUpdateStatus($uid);
        }
        catch (Exception $e)
        {
            Log::write('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL, 'error', true);
        }
        //查询邀请者的名字
        return show(config('code.success'), 'ok', [
            'id' => $resultId,
            'token' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => time(), 'show_type' => 0])),
        ]);
    }

    /**
     * 微信登陆
     */
    public function weixin_login(): void
    {
        $token = input('get.token/s');
        $appid = config('wechat.mp_appid');

        $redirect_uri = urlencode($this->domain . '/web/valentine/weixin_back');
        header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $appid . '&redirect_uri=' . $redirect_uri . '&response_type=code&scope=snsapi_userinfo&state=' . $token . '#wechat_redirect');
        exit;
    }

    /**
     * 微信登陆返回
     */
    public function weixin_back(): void
    {
        $wechat_conf = config('wechat');
        $appid = $wechat_conf['mp_appid'];
        $appsecret = $wechat_conf['mp_secret'];

        $code = input('get.code/s');
        if (empty($code))
        {
            $this->error('微信授权失败！');
        }

        $token = input('get.state/s');
        if (empty($token))
        {
            $this->error('获取token失败！');
        }
        $access_token = session('love.access_token');
        if (empty($access_token) || $access_token === '')
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid . '&secret=' . $appsecret . '&code=' . $code . '&grant_type=authorization_code';
            $access_token = json_decode(file_get_contents($access_token_url), false);
            if (isset($access_token->errcode))
            {
                $this->error('授权失败');
            }
            session('love.access_token', $access_token->access_token);
            session('love.refresh_token', $access_token->refresh_token);
            session('love.openid', $access_token->openid);
        }

        $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . session('love.access_token') . '&openid=' . session('love.openid') . '&lang=zh_CN';
        $user_info = json_decode(file_get_contents($user_info_url), false);
        if (isset($user_info->errcode))
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=' . $appid . '&grant_type=refresh_token&refresh_token=' . session('love.refresh_token');
            $access_token = json_decode(file_get_contents($access_token_url), true);
            if (isset($access_token['access_token'], $access_token['refresh_token'], $access_token['openid']) && !empty($access_token))
            {
                session('love.access_token', $access_token['access_token']);
                session('love.refresh_token', $access_token['refresh_token']);
                session('love.openid', $access_token['openid']);

                $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $access_token['access_token'] . '&openid=' . $access_token['openid'] . '&lang=zh_CN';
                $user_info = json_decode(file_get_contents($user_info_url), false);
                if (isset($user_info->errcode))
                {
                    echo '<h1>错误：</h1>' . $user_info->errcode;
                    echo '<br/><h2>错误信息：</h2>' . $user_info->errmsg;
                    exit;
                }
            } else
            {//失败的话，重新授权登录
                if (40001 === $user_info->errcode)
                {//40001为invalid credential, access_token is invalid or not latest, hints: [ req_id: EfKfY24ce-3ItL5 ]，清空access_token
                    session('love.access_token', null);
                }
                $this->redirect('/web/valentine/weixin_login?token=' . $token);
            }
        }
        //把unionid、headimgurl、name 保存到session里
        session('love.unionid', $user_info->unionid);
        session('love.headimgurl', $user_info->headimgurl);
        session('love.name', $user_info->nickname);
        session('love.sex', $user_info->sex);

        $this->redirect('/web/valentine/add2020?token=' . $token);
    }

    /**
     * 检查session里是否有  unionid、headimgurl、name 这三个参数，如果为空，那么跳转到 微信 或者 qq 登录页面
     * @param string $token app邀请档案传过来的加密数据
     * @param int $share_to 【1：微信；2：qq】
     */
    private function checkLogin($token = '', $share_to = 1): void
    {
        if (1 === $share_to * 1 &&
            (empty(session('love.unionid'))
                || empty(session('love.headimgurl'))
                || empty(session('love.name'))))
        {
            $this->redirect('/web/valentine/weixin_login?token=' . $token);
        } else if (2 === $share_to * 1 &&
            (empty(session('qq.unionid'))
                || empty(session('qq.headimgurl'))
                || empty(session('qq.name'))))
        {
            $this->redirect('/web/valentine/qq_login?token=' . $token);
        }
    }

    /**
     * qq登录
     */
    public function qq_login(): void
    {
        //APP ID：101831016
        //APP Key：0d7d3ce6619c9b3306a8d01386384198
        $app_id = '101831016';
        $app_secret = '0d7d3ce6619c9b3306a8d01386384198';
        $my_url = $this->domain . '/web/valentine/qq_login';

        //注  回调地址必须和该代码域名一致
        if (empty($_GET['code']))
        {//判断是否有code,若无code则去qq第三方接口请求授权
//            $_SESSION['state'] = md5(uniqid(rand(), true));//一串随机的字符串，用于回调时对比参数防止csrf攻击
            //拼接url地址同时url化回调地址并跳转
            $token = input('get.token/s');
            $url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' . $app_id . '&redirect_uri=' . urlencode($my_url) . '&state=' . $token;
            header('location: ' . $url);
        } else
        {
            $token = input('get.state/s');
            //省略一步  使用state判断是否csrf攻击   使用$_SESSION['state']和$_GET['state']进行对比判断授权过程是否被劫持
            //拼接url地址使用code请求并获得access_token
            $url = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=' . $app_id . '&client_secret='
                . $app_secret . '&code=' . $_GET['code'] . '&redirect_uri=' . $my_url;
            //发出请求
            $info = file_get_contents($url);
            //var_dump($info);由于传回来的数据是个字符串，不能直接使用，所以进行变量化
            $params = [];
            parse_str($info, $params);//把传回来的数据参数变量化
            //var_dump($params);变量化后的结果
            /*
             * array(3) {
             *  ["access_token"]=> string(32) "*********"  access_token
             *  ["expires_in"]=> string(7) "7776000"    access_token有效时间
             * ["refresh_token"]=> string(32) "****" }
             * */
            //判断access_token是否存在，如果不存在，那么让用户重新获取，例如：{"error":100019,"error_description":"code to access token error"}
            if (!isset($params['access_token']))
            {
                $this->redirect('/web/valentine/add2020?token=' . $token);
            }

            //使用access_token去请求openid
            $graph_url = 'https://graph.qq.com/oauth2.0/me?access_token=' . $params['access_token'] . '&unionid=1';
            $str = file_get_contents($graph_url);
            //var_dump($str);  请求得到的结果
            //string(83) "callback( {"client_id":"*****","openid":"*****"} ); "
            //callback( {"client_id":"101255228","openid":"89F5D3BB8CEE2B386B02EAC397270E46","unionid":"UID_F3EEF816AB02F7B33521E87A5118B6FA"} );
            //由于得到的结果还是字符串且还不是json类型，只能手动截取json格式的数据
            //判断callback在字符串$str是否存在，如果存在则返回下标，否则false，下标不完全等于false，因为0会被判断为false
            if (strpos($str, 'callback') !== false)
            {
                $lpos = strpos($str, '(');//判断(出现的下标
                $rpos = strrpos($str, ')');//判断)出现的下标，加上r从右边开始查找
                $str = substr($str, $lpos + 1, $rpos - $lpos - 1);//截取字符串
                //从$rpos+1下标 { 处截取  $rpos - $lpos -1 位 ，此时$str的值就为一个json格式的数据了
                // {"client_id":"*****","openid":"*****"}
            }
            $user = json_decode($str, true);//json转对象,存放有返回的数据 client_id ，openid
            //拼接url并访问，用access_token和openid得到用户信息
            $urls = 'https://graph.qq.com/user/get_user_info?access_token=' . $params['access_token'] . '&oauth_consumer_key=' . $app_id . '&openid=' . $user['openid'];
            $rs = file_get_contents($urls);
            $ref = json_decode($rs, true);//得到的用户信息

            //把unionid、headimgurl、name 保存到session里
            session('qq.unionid', $user['unionid']);
            session('qq.headimgurl', $ref['figureurl_qq_1']);
            session('qq.name', $ref['nickname']);
            session('qq.sex', $ref['gender_type']);

            $this->redirect('/web/valentine/add2020?token=' . $token);
        }
    }

    /**
     * 获取用户合盘记录列表
     */
    public function getUserHistoryList()
    {
        $token = input('token/s', '');
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));
        if (empty($str) || strpos($str, 'uid=') === false)
        {
            throw new ApiException($this->LOG_PRE . '参数错误');
        }
        parse_str($str, $params);
        //校验token
        try
        {
            $uid = (int)$params['uid'];
            $data = (new AppSynastryResult())->getUserList($uid, -1);

            $data_list = $data['data'];
            // uid用户id    show_type=>1完整显示合盘结果，0简易引导版
            $token = IAuth::setSign(['uid' => $uid, 'timestamp' => time(), 'show_type' => 1]);
        }
        catch (Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            throw new ApiException('合盘错误：权限认证失败,请稍后重试！');
        }


        return $this->fetch('list2020', [
            'data_list' => $data_list,
            'token' => base64_encode($token),
            'oss' => $this->oss
        ]);
    }

    /**
     * 合盘结果页
     */
    public function get_with_score()
    {
        $id = input('id/d', 0);
        $shareId = input('share_id/d', 0);

        if (!$id && !$shareId)
        {
            throw new ApiException($this->LOG_PRE . '参数错误1');
        }
        $token = input('token/s', '');
        // token AES解密
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));

        if (empty($str) || strpos($str, 'uid=') === false)
        {
            throw new ApiException($this->LOG_PRE . '参数错误2');
        }

        parse_str($str, $params);

        if (empty($params) || !isset($params['uid']) || !$params['uid'])
        {
            throw new ApiException($this->LOG_PRE . '参数错误3');
        }

        // 仅查询当前用户的合盘结果，若未查找到，直接抛出错误页面
        // 通过id查询
        if ($id)
        {
            $result = (new AppSynastryResult())->getInfoById($id);

            if ($result['uid'] != $params['uid'])
            {
                throw new ApiException($this->LOG_PRE . '非法获取');
            }
        } else
        {
            try
            {
                // 通过share_id查询 TODO 添加缓存 若未查询到，则为旧邀请（旧数据）
                $result = (new AppSynastryResult())->field('uid,nickname1,nickname2,avatar1,avatar2,extra')
                    ->where('share_id', $shareId)
                    ->findOrFail()
                    ->toArray();
            }
            catch (\Exception $e)
            {
                throw new ApiException($this->LOG_PRE . '过期查询');
            }
        }

        $records = json_decode($result['extra'], true);
        // 获取完整合盘数据
        $records['type'] = 1;

        $data = (new SynastryData())->getScore($records);

        $score = 0;
        foreach ($data['score'] as $item)
        {
            $score += $item['num'];
        }
        // 区分完整版和简易引导版的展示
        $showType = (isset($params['show_type']) && $params['show_type'] == 1) ? 'get_with_score' : 'simple_result';

        return $this->fetch($showType, [
            'oss' => Env::get('host.photo'),
            'data' => $data,
            'total_score' => $score,
            'result' => $result
        ]);
    }

    public function active2021()
    {
        return $this->fetch('active2021', [
            'appType' => $headers['app-type'] ?? '',
            'domain' => Env::get('host.domain')
        ]);
    }

    /**
     * 2021年七夕节合盘活动
     * @return mixed
     */
    public function index2021()
    {
        // 检查运行环境：true => 运行在APP内 , false => 在APP外的请求
        $rn = $this->checkRuntimeEnvironment();

        // 获取用户的合盘记录
        if ($rn === true)
        {
            //校验token
            try
            {
                $AppSynastryResult = new AppSynastryResult2021();
                $nowTime = time();
                $auth = new Auth();
                $uid = (int)$auth->user['id'];
                // 查询当前用户在排行榜中的排行
//                 $rank = Db::query('select rownum from (select @rownum := @rownum + 1 rownum,b.uid from (SELECT @rownum := 0) r,(
//     select id,uid,max(score) score,from_unixtime(create_time) create_time from wechat_backup_07_18_14_43_00.app_synastry_result_2021 group by uid order by score desc,create_time
// ) b) c where uid=' . $uid);
                $rank = [];

                $userinfo = [
                    'id' => $uid,
                    'rid' => $auth->user['rid'] ?? 0,
                    'nickname' => $auth->user['nickname'],
                    'avatar' => $auth->user['avatar'],
                    'userHistory' => $AppSynastryResult->getUserHighestScore($uid),
                    'userRank' => $rank[0]['rownum'] ?? 0,
                    // 'show_type' => 1  查看合盘结果时，显示完整版结果
                    'token_weixin' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => $nowTime, 'share_to' => 1, 'show_type' => 1])),
                    'token_qq' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => $nowTime, 'share_to' => 2, 'show_type' => 1])),
                ];
            }
            catch (Exception $e)
            {
                throw new ApiException('合盘错误：权限认证失败,请稍后重试！');
            }
        } else
        {
            $userinfo = [
                'id' => 16313677,
                'nickname' => '阿黑',
                'avatar' => '/uploads/20210520/ba0fd6fac1c58c41c0ffb15c893416c6.png',
                'userHistory' => [
                    array(
                        'id' => 1,
                        'nickname1' => '阿黑',
                        'nickname2' => '阿白',
                        'avatar1' => '/uploads/20210520/ba0fd6fac1c58c41c0ffb15c893416c6.png',
                        'avatar2' => 'uploads/avatar/20201214/f12902dd4c64cb85c816c7177256eb70.png',
                        'score' => 542,
                        'relation' => '合作伙伴',
                    ),
                    array(
                        'id' => 5,
                        'nickname1' => '阿黑',
                        'nickname2' => '阿白2',
                        'avatar1' => '/uploads/20210520/ba0fd6fac1c58c41c0ffb15c893416c6.png',
                        'avatar2' => 'uploads/avatar/20201214/f12902dd4c64cb85c816c7177256eb70.png',
                        'score' => 542,
                        'relation' => '合作伙伴',
                    ),
                    array(
                        'id' => 21,
                        'nickname1' => '阿黑',
                        'nickname2' => '阿白',
                        'avatar1' => '/uploads/20210520/ba0fd6fac1c58c41c0ffb15c893416c6.png',
                        'avatar2' => 'uploads/avatar/20201214/f12902dd4c64cb85c816c7177256eb70.png',
                        'score' => 542,
                        'relation' => '合作伙伴',
                    ),
                ],
                'userRank' => 1,
                'token_weixin' => 'RWYzQ2xHTmJyNkZiVjR4c3BaOFIvZzg0clhSbmcwNWxZUGxuczUzSjJBMWNCckFpRXB4NzF5NmgveExpYU1iNmVkN0cybEs3eWlSaFhzUStXVWU1RXc9PQ==',
                'token_qq' => 'TXJoVmJEMHlQd3pWbWtaUnNiV3NRTlZoWHRkc0sxb1AwUGJmT09aTE1sY1VOaUd6dkJJZkMzVElMYW5OSHdWdWdzYmYwU3QwdjlLb0RScWhVRGVZK2c9PQ==',
            ];
        }

        //  获取本命预测商品信息
        $natalGoodData = (new NatalGoods())->getGoods();
        // 获取合盘报告商品
        $synastryReportGoods = (new Goods())->GoodsTypeInfo(17);
        $goodData = array_merge($synastryReportGoods, $natalGoodData);

        $orderModel = new OrdersModel();

        $unlockNum1 = $unlockNum2 = $unlockNum3 = 0;

        foreach ($goodData as $k => $v)
        {
            $goodType = (isset($v['good_type']) && $v['good_type'] === 17) ? 17 : 7;
            $gid = isset($v['id']) ? (int)$v['id'] : 0;
            // 恋爱合盘报告解锁数量
            if ($goodType === 17)
            {
                $unlockNum1 = $v['base_num'] + $orderModel->getTotalPrepaidOrder($goodType, $v['srid']);
            }// 恋爱一生报告解锁数量
            elseif ($gid === 39)
            {
                $unlockNum2 = $v['base_num'] + $orderModel->getTotalPrepaidOrder($goodType, $gid);
            }// 婚姻一生报告解锁数量
            elseif ($gid === 40)
            {
                $unlockNum3 = $v['base_num'] + $orderModel->getTotalPrepaidOrder($goodType, $gid);
            }
        }

        return $this->fetch('', [
            'rn' => $rn,
            'userinfo' => $userinfo,
            'title' => '七夕-找到满分恋人',
            'share_introduction' => '',
            // 获取恋爱报告售卖数量
            'unlockNum1' => $unlockNum1,
            'unlockNum2' => $unlockNum2,
            'unlockNum3' => $unlockNum3,
            'app_type' => $this->request->header('app-type', ''),
            'oss' => $this->oss,
            'domain' => $this->domain,
            /**
             * 七夕敢不敢玩合盘配对，200分以下互删，400分以上扯证！
             * 这个七夕玩把刺激的！你敢吗？
             * 敢不敢和我来合盘，一起挑战最佳拍档！
             * 200分以下咱互删，400分以上一起扯证吧！
             * 七夕敢不敢玩合盘配对，200分以下互删，400分以上扯证！
             * 这个七夕玩把刺激的！你敢吗？
             */
            'share_title' => '看看我们“合不合”？这个七夕敢不敢和我玩合盘配对？',// 分享到朋友圈的文案已写死在页面中
            'share_des' => '200分以下继续狗望狗
400分以上手牵手',
            'height' => input('h/d', 0),
        ]);
    }

    /**
     * 微信/qq档案邀请-填写档案信息页面
     * @return mixed|Json
     * @throws \Exception
     */
    public function add2021()
    {
        $token = input('token/s', '');
        // access-token AES解密
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));
        if (empty($str))
        {
            throw new ApiException($this->LOG_PRE . '参数错误');
        }

        parse_str($str, $params);
        //检查session，如果不存在，那么就直接跳转到登录
        $this->checkLogin2021($token, $params['share_to']);

        //检查输入参数是否正确
        if (!isset($params['uid']))
        {
            throw new ApiException($this->LOG_PRE . 'uid参数为空');
        }
        if (!isset($params['timestamp']))
        {
            throw new ApiException($this->LOG_PRE . 'timestamp参数为空');
        }
        if (!isset($params['share_to']))
        {
            throw new ApiException($this->LOG_PRE . 'share_to参数为空');
        }
        if ($params['share_to'] * 1 !== 1 && $params['share_to'] * 1 !== 2)
        {
            throw new ApiException($this->LOG_PRE . 'share_to参数错误，只能为【1：微信；2：qq】，实际为' . $params['share_to']);
        }
        try
        {
            $record = [
                'uid' => '',
                'name' => '',
                'sex' => '',
                'year' => '',
                'month' => '',
                'day' => '',
                'hour' => '',
                'minute' => '',
                'timezone' => '',
                'birth_country' => '',
                'birth_province' => '',
                'birth_city' => '',
                'live_country' => '',
                'live_province' => '',
                'live_city' => '',
                'comments' => '',
                'isself' => '',
                'long_deg' => '',
                'long_min' => '',
                'ew' => '',
                'lat_deg' => '',
                'lat_min' => '',
                'ns' => '',
                'avatar' => '',
            ];
            $is_user_have_record = 0;
            $signPackage = [];

            $session_avatar = session('qq.headimgurl');
            $session_sex = session('qq.sex');
            $session_name = session('qq.name');
            $session_unionid = session('qq.unionid');
            if (1 === $params['share_to'] * 1)
            {
                $session_avatar = session('love.headimgurl');
                $session_sex = session('love.sex');
                $session_name = session('love.name');
                $session_unionid = session('love.unionid');
            }

            $data = [
                'uid' => $params['uid'],//用户id
                'status' => '0',//0：填写信息；1：已填写；2：提交成功；3：自己邀请自己，提示错误；4：请从qq或者微信打开；【这里只能输入1/2】
                'is_user_have_record' => 0,//根据unionid查询这个用户是否已经存在档案
                'inviter_name' => '',//邀请者的名字
                'share_to' => $params['share_to'],//【1：微信；2：qq】
                'signPackage' => $signPackage,//微信签名
                'unionid' => $session_unionid,
                'timestamp' => $params['timestamp'],
                'record' => $record
            ];

            $AppWechat = new Wechat();
            $AppQq = new AppQq();
            $Record = new Recode();

            //查询是邀请者自己点击进入的邀请h5，那么就直接提示错误
            if (1 === $params['share_to'] * 1)
            {//微信登录
                $wechat_info = $AppWechat->getWechatInfo($params['uid'], 2);
                if ($wechat_info && isset($wechat_info['unionid']) && $wechat_info['unionid'] === $session_unionid)
                {//用户绑定了微信，自己邀请了自己
                    $data['status'] = 3;
                }
            } else
            {
                //qq登录
                $qq_info = $AppQq->getUserQqInfoFromCache($params['uid'], 2);
                if ($qq_info && isset($qq_info['unionid']) && $qq_info['unionid'] === $session_unionid)
                {//用户绑定了qq，自己邀请了自己
                    $data['status'] = 3;
                }
            }

            if (!isset($data['status']) || (isset($data['status']) && 3 !== $data['status'] * 1))
            {
                //根据unionid查询这个用户，是否微信/qq注册过
                if (1 === $params['share_to'] * 1)
                {//微信登录
                    $appWechat = $AppWechat->getWechatInfo($session_unionid, 1);
                    if (isset($appWechat['uid']))
                    {
                        //查询这个用户是否有自己的档案
                        $recordTemp = $Record->getSelfRecode($appWechat);
                        if ($recordTemp)
                        {
                            $record = $recordTemp;
                            $is_user_have_record = 1;
                        }
                    }
                } else
                {
                    //qq登录
                    $appQq = $AppQq->getUserQqInfoFromCache($session_unionid);
                    if (isset($appQq['uid']))
                    {
                        $recordTemp = $Record->getSelfRecode($appQq);
                        if ($recordTemp)
                        {
                            $record = $recordTemp;
                            $is_user_have_record = 1;
                        }
                    }
                }

                $ZlRecordShareAdd = new ZlRecordShareAdd();
                $shareId = $ZlRecordShareAdd
                    ->where('type', $params['share_to'])
                    ->where('code', $session_unionid)
                    ->where('time', $params['timestamp'])
                    ->value('id');

                if ($shareId)
                {//查到了这个用户，需要提示用户已经填写过了
                    $status = 1;
                } else
                {//没有查到这个用户，需要用户填写
                    $status = 0;
                }
                //查询邀请者的名字
                $inviter = (new User())->getUserinfo(['id' => $params['uid']]);
                $inviter_name = $inviter['nickname'];

                //---数据处理---
                //替换type为sex
                if (isset($record['type']))
                {
                    $record['sex'] = $record['type'];
                }
                //替换avatar
                if (isset($record['avatar']))
                {
                    $avatar = $record['avatar'];
                    $preg = "/^http(s)?:\\/\\/.+/";
                    if (!preg_match($preg, $avatar))
                    {
                        $avatar_tmp = substr($avatar, 0, 1);
                        if ($avatar_tmp === '/')
                        {
                            $record['avatar'] = $this->oss . substr($avatar, 1, strlen($avatar));
                        } else
                        {
                            $record['avatar'] = $this->oss . $avatar;
                        }

                    }
                }
                //---数据处理---
                $data = [
                    'uid' => $params['uid'],//用户id
                    'status' => $status,//0：填写信息；1：已填写；2：提交成功；3：自己邀请自己，提示错误；4：请从qq或者微信打开；【这里只能输入1/2】
                    'record' => $record,
                    'is_user_have_record' => $is_user_have_record,//根据unionid查询这个用户是否已经存在档案
                    'inviter_name' => $inviter_name,//邀请者的名字
                    'share_to' => $params['share_to'],//【1：微信；2：qq】
                    'unionid' => $session_unionid,
                    'timestamp' => $params['timestamp'],
                    'share_id' => $shareId,// 用户已填写的档案在zl_record_share_add表中的id
                    'token' => base64_encode(IAuth::setSign(['uid' => $params['uid'], 'timestamp' => time(), 'show_type' => 2])),
                ];
            }

            if (!$is_user_have_record)
            {//如果用户没有档案，那么就把头像、昵称、性别传过去
                $data['record']['avatar'] = $session_avatar;
                $data['record']['sex'] = $session_sex;
                $data['record']['name'] = $session_name;
            } else
            {
                try
                {
                    //如果用户有档案，获取用户的现居地和出生地，省市区的code
                    $locations = Astrolog::getInstance()->getLocations();
                    $item = $locations[$data['record']['birth_country'] . '-' . $data['record']['birth_province'] . '-' . $data['record']['birth_city']];
                    $data['record']['code_birth_country'] = $item['code_country'];
                    $data['record']['code_birth_province'] = $item['code_province'];
                    $data['record']['code_birth_city'] = $item['code_city'];

                    $item = $locations[$data['record']['live_country'] . '-' . $data['record']['live_province'] . '-' . $data['record']['live_city']];
                    $data['record']['code_live_country'] = $item['code_country'];
                    $data['record']['code_live_province'] = $item['code_province'];
                    $data['record']['code_live_city'] = $item['code_city'];
                }
                catch (\Exception $e)
                {
                    //用户有档案，但是【获取用户的现居地和出生地，省市区的code】出错
                    $data['record']['avatar'] = $session_avatar;
                    $data['record']['sex'] = $session_sex;
                    $data['record']['name'] = $session_name;
                }
            }
            if (1 === $params['share_to'] * 1)
            {
                //微信分享的获取微信js签名
                $signPackage = (new Jssdk())->getSignPackage();
            }

            //时间小于10，加0补充
            $data['record']['month'] = str_pad($data['record']['month'], 2, '0', STR_PAD_LEFT);
            $data['record']['day'] = str_pad($data['record']['day'], 2, '0', STR_PAD_LEFT);
            $data['record']['hour'] = str_pad($data['record']['hour'], 2, '0', STR_PAD_LEFT);
            $data['record']['minute'] = str_pad($data['record']['minute'], 2, '0', STR_PAD_LEFT);

            return $this->fetch('add2021', [
                'title' => '填写你的星盘配置',//网页标题
                'share_title' => '快来跟我合个盘',//微信分享标题. 填写你的星盘配置
                'share_introduction' => '200分以下咱互删，400分以上一起扯证吧！',//微信分享内容 一起刷新合盘榜，来拿恋爱报告！
                'share_img' => $this->share_img,
                'signPackage' => $signPackage,//微信签名
                'data' => $data,//带过去的数据
                'oss' => $this->oss,
                'domain' => $this->domain,
            ]);
        }
        catch (\Exception $e)
        {
            throw new ApiException('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . '：[uid=' . $params['uid'] . '&timestamp=' . $params['timestamp'] . '&share_to=' . $params['share_to'] . ']' . $e->getMessage());
        }

    }

    /**
     * 获取用户合盘记录列表
     */
    public function list2021()
    {
        $token = input('token/s', '');
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));
        if (empty($str) || strpos($str, 'uid=') === false)
        {
            throw new ApiException($this->LOG_PRE . '参数错误');
        }
        parse_str($str, $params);
        //校验token
        try
        {
            $uid = (int)$params['uid'];
            $data = (new AppSynastryResult2021())->getUserList($uid);

            // uid用户id    show_type=>1完整显示合盘结果，0简易引导版
            $token = IAuth::setSign(['uid' => $uid, 'timestamp' => time(), 'show_type' => 1]);
        }
        catch (Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            throw new ApiException('合盘错误：权限认证失败,请稍后重试！');
        }


        return $this->fetch('', [
            'data_list' => $data,
            'token' => base64_encode($token),
            'oss' => $this->oss,
            'domain' => $this->domain,
            'height' => input('h/d', 0),
            'title' => '合盘记录',
            'rn' => $this->checkRuntimeEnvironment() // 是否在APP内部的请求
        ]);
    }

    /**
     * 获取合盘分数排行榜
     */
    public function getRankList2021()
    {
        // 数据库获取排行榜前100名
        $dataList = (new AppSynastryResult2021())
            ->field(['max(score) score', 'uid', 'nickname1', 'nickname2', 'avatar1', 'avatar2', 'relation', 'create_time'])
            ->order('score desc,create_time asc')
            ->group('uid')
            ->paginate(100, false, ['page' => 1])
            ->toArray();

        $dataList['code'] = 200;
        $dataList['msg'] = '加载成功';

        return json($dataList);
    }

    /**
     * 档案信息保存
     * @return Json
     */
    public function saveRecord2021(): Json
    {
        //根据unionid查询这个用户是否已经存在档案；0：不存在；1：已存在；
        $is_user_have_record = input('is_user_have_record/d');
        $share_to = input('share_to/d');
        $timestamp = input('timestamp/d');
        $unionid = input('unionid/s', '', 'htmlspecialchars');// 档案名称;
        $uid = input('uid/d');//用户的id，此处是邀请者

        //检查输入参数是否正确
        if (empty($uid))
        {
            return show(config('code.error'), 'uid参数为空');
        }
        if (empty($timestamp))
        {
            return show(config('code.error'), 'timestamp参数为空');
        }
        if (empty($unionid))
        {
            return show(config('code.error'), 'unionid参数为空');
        }
        if (empty($share_to))
        {
            return show(config('code.error'), 'share_to参数为空');
        }
        if ($share_to * 1 !== 1 && $share_to * 1 !== 2)
        {
            return show(config('code.error'), 'share_to参数错误');
        }

        // 档案标签如 自己 朋友 案例
        $isself = 0;//input('isself/d');// 档案是否为自己 0 否 | 1 是（自己的档案无法删除，无法更改为其他标签）
        $comments = '朋友';//标签，默认为朋友

        $name = input('name/s', '', 'htmlspecialchars');// 档案名称
        $type = input('sex/d', 1);// 档案类型  1男 | 2 女 | 3 男同 | 4 女同 | 5 事件 | 6 卜卦
        if (!$type)
        {
            return show(config('code.error'), '请选择性别！');
        }
        if (!in_array($type, [1, 2, 3, 4, 5, 6], true))
        {
            return show(config('code.error'), '性别异常，请重新选择性别');
        }
        $year = input('year/d');// 出生时间-年
        $month = input('month/d');// 出生时间-月
        $day = input('day/d');// 出生时间-日
        $hour = input('hour/d');// 出生时间-时
        $minute = input('minute/d');// 出生时间-分
        $timezone = input('timezone/d', 8);// 出生时间-时区
        $birth_country = input('birth_country/s', '', 'htmlspecialchars');// 出生地点-省
        $birth_province = input('birth_province/s', '', 'htmlspecialchars');// 出生地点-市
        $birth_city = input('birth_city/s', '', 'htmlspecialchars');// 出生地点-区
        $live_country = input('live_country/s', '', 'htmlspecialchars');// 现居地-省
        $live_province = input('live_province/s', '', 'htmlspecialchars');// 现居地-省
        $live_city = input('live_city/s', '', 'htmlspecialchars');// 现居地-省
        $long_deg = input('long_deg/d');// 经度-度
        $long_min = input('long_min/d');// 经度-分
        $ew = input('ew/d');// 东经|西经 1|-1
        $lat_deg = input('lat_deg/d');// 纬度-度
        $lat_min = input('lat_min/d');// 纬度-分
        $ns = input('ns/d');// 南纬北纬  1|-1
        $avatar = input('avatar/s', '', 'htmlspecialchars_decode');// 头像地址

        $is_summer = 0;
        // 只判断大陆地区的夏令时
        if (!in_array($birth_country, $this->noNeedJudgeSummer, true))
        {
            $is_summer = isSummerTime($hour, $minute, 0, $month, $day, $year) ? 1 : 0;// 是否开启夏令时
        }

        $data = [
            'uid' => $uid,
            'name' => $name,
            'type' => $type,
            'year' => $year,
            'month' => $month,
            'day' => $day,
            'hour' => $hour,
            'minute' => $minute,
            'timezone' => $timezone,
            'birth_country' => $birth_country,
            'birth_province' => $birth_province,
            'birth_city' => $birth_city,
            'live_country' => $live_country,
            'live_province' => $live_province,
            'live_city' => $live_city,
            'comments' => $comments,
            'isself' => $isself,
            'long_deg' => $long_deg,
            'long_min' => $long_min,
            'ew' => $ew,
            'lat_deg' => $lat_deg,
            'lat_min' => $lat_min,
            'ns' => $ns,
            'avatar' => $avatar,
            'is_summer' => $is_summer,
            'add_type' => 2,// 1自己创建 2朋友添加 3注册默认创建
            'is_read' => 0, // 是否已读 1已读 0未读
        ];
        $validate = validate('Recode');

        if (!$validate->scene('add')->check($data))
        {
            return show(config('code.error'), (string)$validate->getError());
        }
        try
        {
            if (!$is_user_have_record)
            {//头像是被邀请者，微信/qq授权获取的，需要上传到oss
                $avatarInfo = Util::wxImgUploadOss($avatar, 'uploads/avatar');
                $avatar = $avatarInfo['success'] ? $avatarInfo['url'] : $avatar;
                $data['avatar'] = $avatar;
            }
            // 替换掉oss域名
            $data['avatar'] = str_replace($this->oss, '', $data['avatar']);

            $record_share_add = [
                'uid' => $uid,
                'rid' => 0,
//            'name' => $name, // 没有，用户使用第三方登录的时候，再去获取
                'type' => $share_to,
                'sex' => $type,
                'code' => $unionid,
                'time' => $timestamp,
                'year' => $year,
                'month' => $month,
                'day' => $day,
                'hour' => $hour,
                'minute' => $minute,
//            'timezone' => $timezone, 这里默认都是8
                'birth_country' => $birth_country,
                'birth_province' => $birth_province,
                'birth_city' => $birth_city,
                'live_country' => $live_country,
                'live_province' => $live_province,
                'live_city' => $live_city,
//            'comments' => $comments,
//            'isself' => $isself,
                'long_deg' => $long_deg,
                'long_min' => $long_min,
                'ew' => $ew,
                'lat_deg' => $lat_deg,
                'lat_min' => $lat_min,
                'ns' => $ns,
                'create_time' => $this->request->time()
//            'avatar' => $avatar, //没有，用户使用第三方登录的时候，再去获取
//            'is_summer' => $is_summer,
            ];
            $ZlRecordShareAdd = new ZlRecordShareAdd();
            $shareId = $ZlRecordShareAdd->SaveData($record_share_add);
        }
        catch (\Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            return show(config('code.error'), '服务异常，请稍后重试！');
        }

        try
        {
            $AppSynastryResult2021Model = new AppSynastryResult2021();
            /**
             * 查询用户是否第一次完成邀请
             * 第一次完成邀请时，TODO 赠送恋爱合盘报告8折优惠券
             */
            $withOutSend = $AppSynastryResult2021Model->where('uid', $uid)->count();

            if ($withOutSend <= 0)
            {
                // 开始赠送优惠券
                (new UserCoupon())->activeSendCoupon2($uid);
            }

            // 获取合盘关系与分数 并入库 更新排行榜
            $RecodeCacheModel = new RecodeCacheModel();
            // 获取用户自己的档案
            $orginSelfRecode = $RecodeCacheModel->getRecodeLists($uid, 1);
            $options = [
                'recode1' => $orginSelfRecode,
                'recode2' => $data,// 刚添加的档案
                'type' => 0,// 获取简易数据，只需要分数和最佳关系
            ];
            $synastryResult = (new SynastryData())->getScore($options);

            $synastryResultInsertData = [
                'uid' => $uid,
                'score' => $synastryResult['scoreNum'],
                'share_id' => $shareId,
                'create_time' => $this->request->time(),
                'nickname1' => $orginSelfRecode['name'],
                'nickname2' => $data['name'],
                'avatar1' => $orginSelfRecode['avatar'],
                'avatar2' => $data['avatar'],
                'relation' => $synastryResult['relationText'],
                'extra' => json_encode([
                    'recode1' => $orginSelfRecode,
                    'recode2' => $data
                ]),
            ];

            $resultId = $AppSynastryResult2021Model->saveData($synastryResultInsertData);

        }
        catch (\Exception $e)
        {
            Log::error('[' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL . $this->LOG_PRE . $e->getMessage() . PHP_EOL);
            return show(config('code.error'), '服务异常，请稍后重试！');
        }

        /*
         * share_to  => {1:微信, 2:QQ}
         *
         * 查看合盘结果时，
         * show_type => {1:显示完整版结果, 2:显示简版并提示下载APP进行查看, 3:展示查看排行榜和底部恋爱合盘报告入口}
         * show_tip => 为真则检查是否第一次进入该详情
         */
        $token = base64_encode(IAuth::setSign([
            'uid' => $uid,
            'timestamp' => $this->request->time(),
            'share_to' => 1,
            'show_type' => 3,
            'show_tip' => $withOutSend <= 0, // 是否需要检查 优惠券弹窗展示情况
        ]));

        $link = $this->domain . '/web/valentine/get_with_score2021?id=' . $resultId . '&token=' . $token . '&zhunle_not_show_nav=1';

        // 消息中心添加信息
        $messageData = [
            'status' => 0,
            'is_read' => 0,
            'range' => $uid,
            'type' => 2,
            'reid' => 0,
            'cid' => 0,
            'title' => '好友助力冲榜已完成',
            'content' => '快来查看你和"' . $data['name'] . '"的上榜情况!',
//            'link' => $this->domain . '/web/valentine/index2021?need_auth=1&zhunle_not_show_nav=1',
            // 被邀请者添加完档案信息，给邀请者发送信息，跳转到合盘结果页，该结果页显示查看排行榜按钮，与直接进入的合盘结果页不一致
            'target' => 'link',
            'link' => $link,
            'create_time' => $this->request->time()
        ];
        //发送消息
        try
        {
            //推送消息，跳转到合盘结果
            if ($withOutSend <= 0)
            {
                (new Push())->pushUserMsg($uid, '好友助力冲榜已完成，快来查看你和"' . $data['name'] . '"的上榜情况！同时奖励您一张合盘报告八折券已经发放到您的账户啦~', ['action' => 'valentine2021', 'link' => $link], $messageData['title']);
            } else
            {
                (new Push())->pushUserMsg($uid, $messageData['content'], ['action' => 'valentine2021', 'link' => $link], $messageData['title']);
            }

            //消息中心增加消息
            (new MessageCenter())->pushMessage($uid, $messageData);
            // 记录档案更新状态
            $RecodeCacheModel->setUpdateStatus($uid);
        }
        catch (Exception $e)
        {
            Log::write($this->LOG_PRE . $e->getMessage() . ' [' . $e->getFile() . ':' . $e->getLine() . ']' . PHP_EOL, 'error', true);
        }
        //查询邀请者的名字
        return show(config('code.success'), '加载成功', [
            'id' => $resultId,
            'token' => base64_encode(IAuth::setSign(['uid' => $uid, 'timestamp' => time(), 'show_type' => 2])),
        ]);
    }

    /**
     * 微信登陆
     */
    public function weixin_login2021(): void
    {
        $token = input('get.token/s');
        $appid = config('wechat.mp_appid');

        $redirect_uri = urlencode($this->domain . '/web/valentine/weixin_back2021');
        header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $appid . '&redirect_uri=' . $redirect_uri . '&response_type=code&scope=snsapi_userinfo&state=' . $token . '#wechat_redirect');
        exit;
    }

    /**
     * 微信登陆返回
     */
    public function weixin_back2021(): void
    {
        $wechat_conf = config('wechat');
        $appid = $wechat_conf['mp_appid'];
        $appsecret = $wechat_conf['mp_secret'];

        $code = input('get.code/s');
        if (empty($code))
        {
            $this->error('微信授权失败！');
        }

        $token = input('get.state/s');
        if (empty($token))
        {
            $this->error('获取token失败！');
        }
        $access_token = session('love.access_token');
        if (empty($access_token) || $access_token === '')
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid . '&secret=' . $appsecret . '&code=' . $code . '&grant_type=authorization_code';
            $access_token = json_decode(file_get_contents($access_token_url), false);
            if (isset($access_token->errcode))
            {
                $this->error('授权失败');
            }
            session('love.access_token', $access_token->access_token);
            session('love.refresh_token', $access_token->refresh_token);
            session('love.openid', $access_token->openid);
        }

        $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . session('love.access_token') . '&openid=' . session('love.openid') . '&lang=zh_CN';
        $user_info = json_decode(file_get_contents($user_info_url), false);
        if (isset($user_info->errcode))
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=' . $appid . '&grant_type=refresh_token&refresh_token=' . session('love.refresh_token');
            $access_token = json_decode(file_get_contents($access_token_url), true);
            if (isset($access_token['access_token'], $access_token['refresh_token'], $access_token['openid']) && !empty($access_token))
            {
                session('love.access_token', $access_token['access_token']);
                session('love.refresh_token', $access_token['refresh_token']);
                session('love.openid', $access_token['openid']);

                $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $access_token['access_token'] . '&openid=' . $access_token['openid'] . '&lang=zh_CN';
                $user_info = json_decode(file_get_contents($user_info_url), false);
                if (isset($user_info->errcode))
                {
                    echo '<h1>错误：</h1>' . $user_info->errcode;
                    echo '<br/><h2>错误信息：</h2>' . $user_info->errmsg;
                    exit;
                }
            } else
            {//失败的话，重新授权登录
                if (40001 === $user_info->errcode)
                {//40001为invalid credential, access_token is invalid or not latest, hints: [ req_id: EfKfY24ce-3ItL5 ]，清空access_token
                    session('love.access_token', null);
                }
                $this->redirect('/web/valentine/weixin_login?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
            }
        }
        //把unionid、headimgurl、name 保存到session里
        session('love.unionid', $user_info->unionid);
        session('love.headimgurl', $user_info->headimgurl);
        session('love.name', $user_info->nickname);
        session('love.sex', $user_info->sex);

        $this->redirect('/web/valentine/add2021?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
    }

    /**
     * 检查session里是否有  unionid、headimgurl、name 这三个参数，如果为空，那么跳转到 微信 或者 qq 登录页面
     * @param string $token app邀请档案传过来的加密数据
     * @param int $share_to 【1：微信；2：qq】
     */
    private function checkLogin2021($token = '', $share_to = 1): void
    {
        if (1 === $share_to * 1 &&
            (empty(session('love.unionid'))
                || empty(session('love.headimgurl'))
                || empty(session('love.name'))))
        {
            $this->redirect('/web/valentine/weixin_login2021?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
        } else if (2 === $share_to * 1 &&
            (empty(session('qq.unionid'))
                || empty(session('qq.headimgurl'))
                || empty(session('qq.name'))))
        {
            $this->redirect('/web/valentine/qq_login2021?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
        }
    }

    /**
     * qq登录
     */
    public function qq_login2021(): void
    {
        //APP ID：101831016
        //APP Key：0d7d3ce6619c9b3306a8d01386384198
        $app_id = '101831016';
        $app_secret = '0d7d3ce6619c9b3306a8d01386384198';
        $my_url = $this->domain . '/web/valentine/qq_login2021';

        //注  回调地址必须和该代码域名一致
        if (empty($_GET['code']))
        {//判断是否有code,若无code则去qq第三方接口请求授权
//            $_SESSION['state'] = md5(uniqid(rand(), true));//一串随机的字符串，用于回调时对比参数防止csrf攻击
            //拼接url地址同时url化回调地址并跳转
            $token = input('get.token/s');
            $url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' . $app_id . '&redirect_uri=' . urlencode($my_url) . '&state=' . $token;
            header('location: ' . $url);
        } else
        {
            $token = input('get.state/s');
            //省略一步  使用state判断是否csrf攻击   使用$_SESSION['state']和$_GET['state']进行对比判断授权过程是否被劫持
            //拼接url地址使用code请求并获得access_token
            $url = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=' . $app_id . '&client_secret='
                . $app_secret . '&code=' . $_GET['code'] . '&redirect_uri=' . $my_url;
            //发出请求
            $info = file_get_contents($url);
            //var_dump($info);由于传回来的数据是个字符串，不能直接使用，所以进行变量化
            $params = [];
            parse_str($info, $params);//把传回来的数据参数变量化
            //var_dump($params);变量化后的结果
            /*
             * array(3) {
             *  ["access_token"]=> string(32) "*********"  access_token
             *  ["expires_in"]=> string(7) "7776000"    access_token有效时间
             * ["refresh_token"]=> string(32) "****" }
             * */
            //判断access_token是否存在，如果不存在，那么让用户重新获取，例如：{"error":100019,"error_description":"code to access token error"}
            if (!isset($params['access_token']))
            {
                $this->redirect('/web/valentine/add2021?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
            }

            //使用access_token去请求openid
            $graph_url = 'https://graph.qq.com/oauth2.0/me?access_token=' . $params['access_token'] . '&unionid=1';
            $str = file_get_contents($graph_url);
            //var_dump($str);  请求得到的结果
            //string(83) "callback( {"client_id":"*****","openid":"*****"} ); "
            //callback( {"client_id":"101255228","openid":"89F5D3BB8CEE2B386B02EAC397270E46","unionid":"UID_F3EEF816AB02F7B33521E87A5118B6FA"} );
            //由于得到的结果还是字符串且还不是json类型，只能手动截取json格式的数据
            //判断callback在字符串$str是否存在，如果存在则返回下标，否则false，下标不完全等于false，因为0会被判断为false
            if (strpos($str, 'callback') !== false)
            {
                $lpos = strpos($str, '(');//判断(出现的下标
                $rpos = strrpos($str, ')');//判断)出现的下标，加上r从右边开始查找
                $str = substr($str, $lpos + 1, $rpos - $lpos - 1);//截取字符串
                //从$rpos+1下标 { 处截取  $rpos - $lpos -1 位 ，此时$str的值就为一个json格式的数据了
                // {"client_id":"*****","openid":"*****"}
            }
            $user = json_decode($str, true);//json转对象,存放有返回的数据 client_id ，openid
            //拼接url并访问，用access_token和openid得到用户信息
            $urls = 'https://graph.qq.com/user/get_user_info?access_token=' . $params['access_token'] . '&oauth_consumer_key=' . $app_id . '&openid=' . $user['openid'];
            $rs = file_get_contents($urls);
            $ref = json_decode($rs, true);//得到的用户信息

            //把unionid、headimgurl、name 保存到session里
            session('qq.unionid', $user['unionid']);
            session('qq.headimgurl', $ref['figureurl_qq_1']);
            session('qq.name', $ref['nickname']);
            session('qq.sex', $ref['gender_type']);

            $this->redirect('/web/valentine/add2021?token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1');
        }
    }

    /**
     * 合盘结果页
     */
    public function get_with_score2021()
    {
        $id = input('id/d', 0);
        $shareId = input('share_id/d', 0);

        if (!$id && !$shareId)
        {
            throw new ApiException($this->LOG_PRE . '参数错误1');
        }
        $token = input('token/s', '');
        // token AES解密
        $str = (new Aes())->decryptWithOpenssl(base64_decode($token));

        if (empty($str) || strpos($str, 'uid=') === false)
        {
            throw new ApiException($this->LOG_PRE . '参数错误2');
        }

        parse_str($str, $params);

        if (empty($params) || !isset($params['uid']) || !$params['uid'])
        {
            throw new ApiException($this->LOG_PRE . '参数错误3');
        }

        try
        {
            $where = $id ? ['id' => $id] : ['share_id' => $shareId];
            $result = (new AppSynastryResult2021())->field('uid,nickname1,nickname2,avatar1,avatar2,extra')
                ->where($where)
                ->findOrFail()
                ->toArray();
        }
        catch (\Exception $e)
        {
            throw new ApiException($this->LOG_PRE . '未知合盘');
        }

        $records = json_decode($result['extra'], true);
        // 获取完整合盘数据
        $records['type'] = 1;

        $data = (new SynastryData())->getScore($records);

        $score = 0;
        foreach ($data['score'] as $item)
        {
            $score += $item['num'];
        }
        // 区分完整版和简易引导版的展示
        $showType = (isset($params['show_type']) && $params['show_type'] != 2) ? 'get_with_score2021' : 'simple_result2021';
        $tips = '';
        if ($showType === 'simple_result2021')
        {
            /**
             * 5-300分    85%-90%
             * 300-400分    90%-95%
             * 400-500分     96%-98%
             * 500分以上    99%
             */
            if ($score >= 500)
            {
                $per = 99;
            } elseif ($score >= 400)
            {
                $per = random_int(96, 98);
            } elseif ($score >= 300)
            {
                $per = random_int(91, 95);
            } else
            {
                $per = random_int(85, 90);
            }
            $tips = '你与Ta的合盘分数打败了' . $per . '%的用户';
        }

        // 合盘结果分享文案
        if ($score < 300)
        {
            $shareTitle = '七夕来合盘！这个合盘分析太准了！';
            $shareDes = '我俩要继续狗望狗了';
        } else
        {
            $shareTitle = '奔走相告！这个七夕找到和我最合的人了！';
            $shareDes = '决定手牵手了！';
        }

        $app_type = $this->request->header('app-type', '');

        $unlockNum1 = 0;
        if ($params['show_type'] == 3)
        {
            $orderModel = new OrdersModel();
            // 获取合盘报告商品
            $synastryReportGoods = (new Goods())->GoodsTypeInfo(17);

            foreach ($synastryReportGoods as $k => $v)
            {
                $goodType = (isset($v['good_type']) && $v['good_type'] === 17) ? 17 : 7;
                // 恋爱合盘报告解锁数量
                if ($goodType === 17)
                {
                    $unlockNum1 = $v['base_num'] + $orderModel->getTotalPrepaidOrder($goodType, $v['srid']);
                }
            }
        }


        /**
         * TODO 是否展示优惠券的弹窗
         * 仅在用户完成邀请，第一次点击进入合盘结果页
         */
        $isShowCouponTip = false;

        return $this->fetch($showType, [
            'rn' => $this->checkRuntimeEnvironment(),
            'index_url' => $this->domain . '/web/valentine/index2021?zhunle_not_show_nav=1&zhunle_nav_text_color=1',
            'oss' => $this->oss,
            'data' => $data,
            'total_score' => $score,
            'result' => $result,
            'height' => input('h/d', 0),
            'title' => '合盘结果',
            'show_type' => $params['show_type'],// 页面展示样式
            'is_show_coupon' => $isShowCouponTip && $app_type !== '' && $params['show_type'] == 3,
            'app_type' => $app_type,
            'share_title' => $shareTitle,
            'share_des' => $shareDes,
            'share_link' => $this->domain . '/web/valentine/get_with_score2021.html?id=' . $id . '&token=' . $token . '&zhunle_not_show_nav=1&zhunle_nav_text_color=1&share=1',
            'tips' => $tips,// 不显示完整版的时候，增加提示信息
            'unlockNum1' => $unlockNum1,
        ]);
    }
}
